package com.eling.elcms.system.service.impl;

import com.eling.elcms.core.exception.BusinessException;
import com.eling.elcms.system.model.ValidateCode;
import com.eling.elcms.system.service.IMobileValidateService;
import com.shcm.send.OpenApi;
import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.sql.DataSource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

@Service
@Transactional
public class MobileValidateImpl implements IMobileValidateService,BeanFactoryAware{
	
	private static final Logger log = LoggerFactory.getLogger(MobileValidateImpl.class);
	
	private BeanFactory beanFactory;
	private JdbcTemplate jdbcTemplate;
	private final String selectSql =  "SELECT * FROM sms_validate_code WHERE phone = ? ";
	private final String deleteSql = "DELETE  FROM sms_validate_code WHERE phone = ? ";
	private final String insertSql = "INSERT INTO sms_validate_code  (code, effectiveTime,phone) values (?,?,?)";
	private final String updateSql = "UPDATE sms_validate_code SET code = ?, effectiveTime = ?  WHERE phone = ? ";
	private HashMap<String,Long> phoneNoMap = new HashMap<String,Long>();
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public String getValidateCode(String openidAndPhone){
		Long time=phoneNoMap.get(openidAndPhone);
		if(time!=null){
			if(System.currentTimeMillis()-phoneNoMap.get(openidAndPhone)<60000){
				throw new BusinessException("发送过于频繁，请稍后再试");
			}
		}
		phoneNoMap.put(openidAndPhone, System.currentTimeMillis());
		
		String code = createCode();
		try {
			List list = getJdbcTemplate().query(selectSql, new Object[] { openidAndPhone },new ProductModleRowMapper());
			if(list.size()>0){//已经有短信验证码 修改验证码和时间
				modityValidateCode(openidAndPhone,code);
			}else{//没有新增
				addValidateCode(openidAndPhone,code);
			}
		} catch (EmptyResultDataAccessException e) {
			log.debug("手机为={"+openidAndPhone+"}的验证码生成错误！",e);
		}
		return code;
	}
	
	private void addValidateCode(String openidAndPhone,String code) {
		getJdbcTemplate().update(insertSql, new Object[] {code,new Date(),openidAndPhone});
		log.debug("新增手机={}的验证码为={}", openidAndPhone,code);
	}

	private void modityValidateCode(String openidAndPhone,String code) {
		getJdbcTemplate().update(updateSql, new Object[] {code,new Date(),openidAndPhone});
		log.debug("修改手机={}的验证码为={}", openidAndPhone,code);
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public boolean validateCode(String openidAndPhone, String code) {
		try {
			List<ValidateCode> list = getJdbcTemplate().query(selectSql, new Object[] { openidAndPhone },new ProductModleRowMapper());
			if(list.size()>0){
				ValidateCode vc = list.get(0);
				long time= new Date().getTime() - vc.getStartTime();
				if(time>EFF_TIME){
					log.debug("手机为={}的验证码失效！",openidAndPhone);
					return false;
				}else{
					if(vc.getCode().equals(code)){//验证正确
						log.debug("手机为={}的验证码正确, 验证码为={}", openidAndPhone,code);
						getJdbcTemplate().update(deleteSql, new Object[] {openidAndPhone});
						log.debug("手机={}验证成功并清除数据！", openidAndPhone);
						return true;
					}else{
						log.debug("根据手机={}验证码错误！", openidAndPhone);
						return false;
					}
				}
			}else{
				log.debug("未找到手机为={}的验证码！",openidAndPhone);
				return false;
			}
		} catch (EmptyResultDataAccessException e) {
			log.debug("未找到手机为={"+openidAndPhone+"}的验证码！",e);
			return false;
		}
	}
	
	/**
	 * 生成 i 长度 随机数作为验证码
	 * 
	 * @return
	 */
	private String createCode() {
		int length = 6; // 验证码长度
		return RandomStringUtils.random(length, "0123456789");
	}
	
	//短信接口配置信息
	//url
	@Value("${sms.sOpenUrl}")
	private String sOpenUrl;
	// 接口帐号
	@Value("${sms.account}")
	private String account;
	// 接口密钥
	@Value("${sms.authkey}")
	private String authkey;
	// 通道组编号
	@Value("${sms.cgid}")
	private int cgid;
	// 默认使用的签名编号(未指定签名编号时传此值到服务器)
	@Value("${sms.csid}")
	private int decsid;
	
	public boolean sendOnce(String mobile, String content ,Integer csid)throws Exception{
		if(csid == null ){
			//如果传入参数为空 走默认
			csid =decsid;
		}
		// 发送参数
		OpenApi.initialzeAccount(sOpenUrl, account, authkey, cgid, csid);
		log.info("初始化参数成功");
		
		double dReamin = OpenApi.getBalance();
		log.info("账户余额：{}", dReamin);

		//String sSend = new String(content.getBytes("UTF-8"), "UTF-8");
		int nRet = OpenApi.sendOnce(mobile, content, cgid, csid, null);
		if(nRet > 0){
			log.info("发送成功！nret：{}发送内容：{}", nRet, content);
			return true;
		}else
			log.info("发送失败！nret：{}", nRet);
		return false;
	}
 
	
	@SuppressWarnings("rawtypes")
	private   class  ProductModleRowMapper  implements  RowMapper{  
        public Object mapRow(final ResultSet rs, final int rowNum) throws SQLException {  
        	SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        	ValidateCode vc = new ValidateCode();  
        	vc.setCode((String)rs.getString("code"));
        	try {
				vc.setStartTime(sdf.parse(rs.getString("effectiveTime")).getTime());
			} catch (ParseException e) {
				log.debug("验证码生效时间异常！",e);
			}
            return vc;  
        }  
    }  
	
	private JdbcTemplate getJdbcTemplate() {
		if (null == jdbcTemplate) {
			DataSource ds = (DataSource) beanFactory.getBean("dataSource");
			jdbcTemplate = new JdbcTemplate(ds);
		}
		return jdbcTemplate;
	}
	
	@Override
	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		this.beanFactory = beanFactory;
	}


}
